package mathy.wili.extract_srcFile.java;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import _a.Config26;
import mathy.c.Ca;
import mathy.c.Coms26a;
import mathy.c.LogConf;
import mathy.wili.c.Class9;
import mathy.wili.c.asm.Asm9;
import mathy.wili.c.asm.AsmItems;
/**
 * List of field|method|constructor|class.
 * @author weila 2021年2月27日
 */
public class AsmItemList extends AsmItems {
	/**
	 * 	Asm 通过对初始化的访问，取得较多的属性定义时相关元素（属性 | 方法 | 类型）
	 */
	static final Map<Class<?>, AsmItemList> clsToAttsInfoMap = new HashMap<>();

	static final Map<Class<?>, AsmItemList> objToAttsInfoMap = new HashMap<>();
	public String toString() {
		return list.size() + list.toString();
	}

	public AsmItemList(AsmItem from) {
		super(from);
	}

	public void sort() {
		Collections.sort(list, new Comparator<AsmItem>() {
			@Override
			public int compare(AsmItem o1, AsmItem o2) {
				return o1.lineNo - o2.lineNo;
			}
		});
	}

	public void vistItmes(int depth) {
		for (int i = 0; i < list.size(); i++) {
			AsmItem item = list.get(i);
			if (item.ele instanceof Field) {
				Field fd = (Field) item.ele;
				Visit26.visitField(depth, fd);
			} else if (item.ele instanceof Executable) {
				Executable fd = (Executable) item.ele;
				Visit26.visitMethod("", fd.getDeclaringClass(), fd);
			} else if (item.ele instanceof Class) {
			} else {
				Ca.asert(false, item.get());
			}
		}
	}

	public void deepVisit(int depth) {
		++depth;
		for (int i = 0; i < list.size(); i++) {
			AsmItem item = list.get(i);
			if (item.ele instanceof Field) {
				Field fd = (Field) item.ele;
			} else if (item.ele instanceof Executable) {
				Executable fd = (Executable) item.ele;
			} else if (item.ele instanceof Class) {
			} else {
				Ca.asert(false, item.get());
			}
		}
		for (int i = 0; i < list.size(); i++) {
			deepVisitItem(depth, i);
		}
	}
	static int inc;
	static Class<?> classOfItem(AnnotatedElement ele) {
		if (ele instanceof Executable) {
			Class<?> ret = ((Executable) ele).getDeclaringClass();
			return ret;
		}
		if (ele instanceof Field)
			return ((Field) ele).getDeclaringClass();
		return (Class<?>) ele;
	}
	/**
	 * 
	 */
	private static final Set<String> visitedItemSet = new HashSet<>();
	private void deepVisitItem(int depth, int index) {
		if (id == 82 && index == 4)
			Ca.pause();
		AsmItem item = list.get(index);
		if (depth > item.maxDepth)
			return;
		if (++inc == 3638)
			Ca.pause();
		Ca.debug(1, inc, ",deepVisitItem: ");
		String itemSt = item.key();
		if (itemSt.contains("doCode"))
			Ca.pause();
		final Class<?> eleCls = classOfItem(item.ele);
		if (eleCls.isAnonymousClass()) {
			depth++;
			//eg. wili.c.asm.FindPutField9$1
			Method[] mm = eleCls.getDeclaredMethods();
			for (Method md : mm) {
				if (md.getName().equals("doField"))
					Ca.pause();
				if ("".isEmpty()) {
					AsmItem item2 = new AsmItem(md);
					if (!visitedItemSet.add(item2.toString()))
						continue;
					Visit26.visitMethod_and_deepVisit_methodContent(depth, item2);
				} else {
					Visit26.visitMethod("", eleCls, md);
				}
				Coms26.visitSuperAbstractMethodOf(md);
			}
			Field[] ff = eleCls.getDeclaredFields();
			for (Field fd : ff) {
				Visit26.visitField(depth, fd);
			}
			return;
		} else if (eleCls.isLocalClass() || eleCls.isSynthetic() || eleCls.isArray() || eleCls.isAnonymousClass()) {
			return;
		} else if (eleCls.isEnum() || eleCls.isAnnotation() || Config26.FILES_tobe_copied.contains(eleCls)
				|| Coms26a.isIn_tobeCopiedPackage(eleCls.getName())) {
			Cont26.addMustBeCopiedFile(eleCls);
			if (eleCls.isEnum() || eleCls.isAnnotation())
				return;
		}
		//ClsRange cRange = ClsRange.clsRangeOf(eleCls);
		if (!visitedItemSet.add(itemSt))
			return;
		Cont26.visitConcreteClass_andItsSuperClass(eleCls);
		if (item.ele instanceof Method || item.ele instanceof Constructor<?>) {
			Executable method = (Executable) item.ele;
			visitBlock(depth, eleCls, method);
			Visit26.visitMethod_and_deepVisit_methodContent(depth, item);
			if (method instanceof Method)
				Coms26.visitSuperAbstractMethodOf((Method) method);
			if (itemSt.contains("PutFieldItem"))
				Ca.pause();
			for (Class<?> cls : method.getParameterTypes()) {
				Cont26.visitConcreteClass_andItsSuperClass(cls);
			}
			return;
		} else if (item.ele instanceof Field) {
			//有n个属性引用，但只有1个属性定义。
			Field field = (Field) item.ele;
			if (eleCls.isEnum())
				return;
			Visit26.visitField(depth, field);
			if ("".isEmpty()) {
				Coms26.deepVisitField_from_asmInit(item, this);
			}
		} else if (item.ele instanceof Class<?>) {
			RangesOfClsMember mmrange = RangesOfClsMember.getInst(depth, eleCls);
			if (mmrange == null)
				return;
			mmrange.visited = true;
			return;//don't access class initiatively.
		} else {
			Ca.asert(false, item.getClass());
		}
		if (eleCls.isAnonymousClass()) {//eg. wili.c.asm.FindPutField9$1
		}
		if (eleCls.equals(LogConf.class))
			Ca.pause();
		//对初始块中的内容做浅层访问
		if (eleCls.equals(Asm9.class))
			Ca.pause();
	}

	boolean visitStaticBlock(int depth, Class<?> eleCls, Executable ele) {
		//ClsRange.clsRangeOf(eleCls);
		if (INITED_ClassSet.add(eleCls.getName() + ":C")) {//类块
			AsmItemList items = new AsmItemList(this.fromItem);
			Coms26.visitStaticFinalSimpleFields(eleCls);
			Asm9.findInInit_forCalledMethods_and_fields(eleCls, 1, null, Config26.Class_filter, items);
			ClsRange crange = ClsRange.clsRangeOf(eleCls);
			if (crange == null) {
				if (eleCls.isAnonymousClass())
					return false;
				Ca.asert(false, eleCls);
			}
			crange.staticInited = true;
			return true;
		}
		return false;
	}

	/**
	 * 	访问静态块、静态属性  | 对象块，对象属性
	 *  @return  本元素若是属性，则返回其初始化值中的元素信息
	 */
	void visitBlock(int depth, Class<?> eleCls, Executable ele) {
		if ("456".isEmpty())
			return;
		Ca.asert(ele instanceof Executable, ele);
		AsmItemList items = new AsmItemList(this.fromItem);
		if (ele instanceof Method && Class9.isStaticMethod((Method) ele)) {
			//访问了静态方法|属性
			if (!visitStaticBlock(depth, eleCls, ele))
				return;
		} else {
			//访问了对象方法|属性
			visitStaticBlock(depth, eleCls, ele);
			//初始化对象块。
			if (INITED_ClassSet.add(eleCls.getName() + ":O")) {//对象块
				Asm9.findInInit_forCalledMethods_and_fields(eleCls, 2, null, Config26.Class_filter, items);
				ClsRange crange = ClsRange.clsRangeOf(eleCls);
				if (crange == null)
					return;
				crange.objInited = true;
			} else {
				return;
			}
		}
		for (AsmItem item2 : items.list) {
			if (item2 == null)
				continue;
			boolean onlySlef = "".isEmpty();//这个似乎影响结果
			if (!onlySlef || eleCls.equals(item2.getCls())) {//只调用本类中的方法。
				item2.maxDepth = depth + 99;
				this.list.add(item2);
			}
		}
	}
	static final Set<String> INITED_ClassSet = new HashSet<>();
	@Override
	public AsmItem adde(int lineNo, AnnotatedElement ele) {
		if (id == 3)
			if (list.size() == 2)
				Ca.pause();
		AsmItem ele2 = new AsmItem(this, ele, lineNo);
		if (this.fromItem != null)
			ele2.maxDepth = this.fromItem.maxDepth;
		list.add(ele2);
		return ele2;
	}
}
